﻿using System;
using System.IO.Ports;
using System.Text;
using System.Threading;

namespace RFIDMifare
{
    public class SerialPortManager
    {
        #region delegate
        public delegate void SerialPortReceivedEventHandler(string data);
        #endregion

        #region 枚举
        /// <summary>
        /// 数据传输类型
        /// </summary>
        public enum TransmissionType { Text, Hex }
        #endregion

        #region 内部变量
        //串口对象
        private SerialPort serialPort = new SerialPort();
        #endregion

        #region 属性

        /// <summary>
        /// 端口状态
        /// </summary>
        public bool IsOpen
        {
            get
            {
                return serialPort.IsOpen;
            }
        }

        /// <summary>
        /// 波特率
        /// </summary>
        public string BaudRate { get; set; }

        /// <summary>
        /// 校验位
        /// </summary>
        public string Parity { get; set; }

        /// <summary>
        /// 停止位
        /// </summary>
        public string StopBits { get; set; }

        /// <summary>
        /// 数据位
        /// </summary>
        public string DataBits { get; set; }

        /// <summary>
        /// 端口名
        /// </summary>
        public string PortName { get; set; }

        /// <summary>
        /// 当前传输类型
        /// </summary>
        public TransmissionType CurrentTransmissionType { get; set; }

        #endregion

        #region 事件
        public event SerialPortReceivedEventHandler SerialPortDataReceived;
        #endregion

        #region 构造方法
        public SerialPortManager()
        {
            PortName = string.Empty;
            BaudRate = string.Empty;
            Parity = serialPort.Parity.ToString();
            StopBits = serialPort.StopBits.ToString();
            DataBits = string.Empty;
            serialPort.DataReceived += DataReceived;
        }

        public SerialPortManager(string baudRate, string parity, string stopBits, string dataBits, string portName)
        {
            PortName = portName;
            BaudRate = baudRate;
            Parity = parity;
            StopBits = stopBits;
            DataBits = dataBits;
            serialPort.DataReceived += DataReceived;
        }

        #endregion

        #region 串口操作方法
        /// <summary>
        /// 打开端口
        /// </summary>
        public void Open()
        {
            Close();

            //设置串口属性
            serialPort.BaudRate = int.Parse(BaudRate);    //波特率
            serialPort.DataBits = int.Parse(DataBits);    //数据位
            serialPort.StopBits = (StopBits)Enum.Parse(typeof(StopBits), StopBits);     //停止位
            serialPort.Parity = (Parity)Enum.Parse(typeof(Parity), Parity);             //校验位
            serialPort.PortName = PortName;   //端口号
            serialPort.Open();  //打开串口
        }

        /// <summary>
        /// 关闭端口
        /// </summary>
        public void Close()
        {
            if (serialPort.IsOpen)
            {
                serialPort.Close();
            }
        }
        #endregion

        #region 数据转换方法
        /// <summary>
        /// 十六进制字符串转byte数组
        /// </summary>
        /// <param name="msg">要被转的字符串</param>
        /// <returns>16进制byte数组</returns>
        private byte[] HexToByte(string msg)
        {
            //移除空格
            msg = msg.Replace(" ", "");
            //create a byte array the length of the
            //divided by 2 (Hex is 2 characters in length)
            byte[] comBuffer = new byte[msg.Length / 2];
            //loop through the length of the provided string
            for (int i = 0; i < msg.Length; i += 2)
                //convert each set of 2 characters to a byte
                comBuffer[i / 2] = (byte)Convert.ToByte(msg.Substring(i, 2), 16);

            return comBuffer;
        }

        /// <summary>
        /// byte数组转string
        /// </summary>
        /// <param name="comByte">要被转换的byte数组</param>
        /// <returns>16进制字符串</returns>
        private string ByteToHex(byte[] comByte)
        {
            //create a new StringBuilder object
            StringBuilder builder = new StringBuilder(comByte.Length * 3);
            //loop through each byte in the array
            foreach (byte data in comByte)
                //convert the byte to a string and add to the stringbuilder
                builder.Append(Convert.ToString(data, 16).PadLeft(2, '0').PadRight(3, ' '));
            //return the converted value
            return builder.ToString().ToUpper();
        }
        #endregion

        #region 串口数据收发方法
        /// <summary>
        /// 串口写数据
        /// </summary>
        /// <param name="msg"></param>
        public void WriteData(string msg)
        {
            if (serialPort.IsOpen == false)
            {
                throw new Exception("串口未打开");
            }
            switch (CurrentTransmissionType)
            {
                case TransmissionType.Text:
                    //send the message to the port
                    serialPort.Write(msg);
                    //SendEndOfLine();
                    break;
                case TransmissionType.Hex:
                    //convert the message to byte array
                    byte[] newMsg = HexToByte(msg);
                    //send the message to the port
                    serialPort.Write(newMsg, 0, newMsg.Length);
                    break;
            }
        }

        /// <summary>
        /// 数据接收方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            Thread.Sleep(100);
            string msg;
            switch (CurrentTransmissionType)
            {
                //文本显示
                case TransmissionType.Text:
                    msg = serialPort.ReadExisting();
                    if (msg.Length > 0)
                    {
                        SendDataToEvent(msg);
                    }
                    break;
                //16进制显示
                case TransmissionType.Hex:
                    int bytes = serialPort.BytesToRead;
                    byte[] buffer = new byte[bytes];
                    serialPort.Read(buffer, 0, bytes);
                    if (bytes > 0)
                    {
                        msg = ByteToHex(buffer);
                        SendDataToEvent(msg);
                    }

                    break;
            }
        }
        #endregion

        /// <summary>
        /// 发送串口数据到事件中
        /// </summary>
        /// <param name="msg"></param>
        private void SendDataToEvent(string msg)
        {
            if (SerialPortDataReceived == null)
                return;

            SerialPortDataReceived(msg);
        }

    }
}
